package optimizer;

import midcode.MidCode;
import midcode.OPType;

import java.util.ArrayList;
import java.util.HashMap;

public class FuncBlock {
    private final MidCode midCode;
    private String funcName;
    private final StartBlock startBlock;
    private final ArrayList<BasicBlock> basicBlocks;
    private final EndBlock endBlock;
    private final HashMap<String, BasicBlock> labelToBasicBlock;

    public FuncBlock(MidCode midCode) {
        this.midCode = midCode;
        startBlock = new StartBlock(midCode);
        basicBlocks = new ArrayList<>();
        endBlock = new EndBlock();
        labelToBasicBlock = new HashMap<>();
    }

    public void addBasicBlock(BasicBlock basicBlock) {
        basicBlocks.add(basicBlock);
        funcName = midCode.getDst();
    }

    public void addLabel(String label, BasicBlock basicBlock) {
        labelToBasicBlock.put(label, basicBlock);
    }

    public void setRelation() {
        for (int i = 0; i < basicBlocks.size(); i++) {
            MidCode basicBlockLastMidCode = basicBlocks.get(i).getLastMidCode();
            OPType opType = basicBlockLastMidCode.getOpType();
            if (opType == OPType.BNE || opType == OPType.BEQ) {
                String label = basicBlockLastMidCode.getDst();
                BasicBlock basicBlock = labelToBasicBlock.get(label);
                link(basicBlocks.get(i), basicBlock);
                link(basicBlocks.get(i), basicBlocks.get(i + 1));
            } else if (opType == OPType.GOTO) {
                String label = basicBlockLastMidCode.getDst();
                BasicBlock basicBlock = labelToBasicBlock.get(label);
                link(basicBlocks.get(i), basicBlock);
            } else if (opType == OPType.EXIT || opType == OPType.RET_INT || opType == OPType.RET_VOID) {
                link(basicBlocks.get(i), endBlock);
            } else {
                link(basicBlocks.get(i), basicBlocks.get(i + 1));
            }
        }
    }

    private void link(BasicBlock preBlock, BasicBlock nextBlock) {
        preBlock.addNextBlock(nextBlock);
        nextBlock.addPreBlock(preBlock);
    }

//    public void setDefUse() {
//        for (BasicBlock basicBlock : basicBlocks) {
//            basicBlock.setDefUseSet();
//        }
//        boolean stopFlag = false;
//        while (stopFlag) {
//            stopFlag = true;
//            for (int i = basicBlocks.size() - 1; i >= 0; i--) {
//                if (basicBlocks.get(i).setDefUseOutSet()) {
//                    stopFlag = false;
//                }
//                basicBlocks.get(i).setDefUseInSet();
//            }
//        }
//        for (int i = basicBlocks.size() - 1; i >= 0; i--) {
//            basicBlocks.get(i).setDefUse();
//        }
//    }
//
//    public void valSpread() {
//        for (BasicBlock b : basicBlocks) {
//            b.valSpread();
//        }
//    }
}

